package org.eclipse.epsilon.emc.jdt2;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.antlr.runtime.CommonToken;
import org.eclipse.epsilon.common.parse.AST;
import org.eclipse.epsilon.eol.exceptions.EolRuntimeException;
import org.eclipse.epsilon.eol.execute.context.IEolContext;
import org.eclipse.epsilon.eol.execute.operations.declarative.SelectOperation;
import org.eclipse.epsilon.eol.parse.EolParser;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;

public class QuickSelectOperationBase extends SelectOperation {
	List<HashMap<String, IJavaElement>> list = new ArrayList<HashMap<String, IJavaElement>>();

	protected String type;
	protected ASTReflection astModel;
	protected List<IJavaProject> javaProjects;

	protected String tmpName = null;
	protected AST nameAst = null;
	protected AST tmpAst = null;

	public QuickSelectOperationBase(String type, ASTReflection astModel,
			List<IJavaProject> javaProjects) {
		super();
		this.type = type;
		this.astModel = astModel;
		this.javaProjects = javaProjects;
	}

	@Override
	public Object execute(Object target, AST operationAst, IEolContext context)
			throws EolRuntimeException {
		// TODO Auto-generated method stub
		if (target instanceof QuickList) {
			ArrayList<Object> resultList = new ArrayList<Object>();

			System.out.println(operationAst.getText());
			printAST(operationAst, "");

			if (checkAST(operationAst)) {
				System.out.println("HAS NAME AND GOOD!");
				operationAst = transformedAst(operationAst);
			}

			// if (hasNot(operationAst)) {
			// System.out.println("HAS NOT!");
			// System.out.println(operationAst.getChild(0).getChildIndex());
			// }
			
			if(operationAst.getChild(0).getText().equals("select")){
				System.out.println("SODFJOEWIJFOEWJFOIEWJF");
				operationAst = operationAst.getChild(0);
			}

			if (operationAst.getChild(1).getText().equals("=")
					&& (operationAst.getChild(1).getChild(0).getChild(1)
							.getText().equals("name") || operationAst
							.getChild(1).getChild(0).getChild(1).getText()
							.equals("fullName"))) { // only with one name
													// constraint
				String s = (String) context.getExecutorFactory().executeAST(
						operationAst.getChild(1).getChild(1), context);
				resultList.addAll(SearchUtil.search(type, astModel,
						javaProjects, s, true));
				// } else if (hasName(operationAst)) { // has name constraint
				// and other
				// // contraint(s)
				// resultList.addAll(SearchUtil.search(type, astModel,
				// javaProjects, tmpName, true));
				//
				// System.out.println("has name= --- " + resultList.size());
				// System.out.println("SUPER EXECUTION NEEDED!");
				//
				// tmpName = null;
				// return super.execute(resultList, operationAst, context);
			} else if (checkAST(operationAst)) { // can use search engine
				operationAst = transformedAst(operationAst);
				
				printAST(operationAst, "");
				
				resultList.addAll(SearchUtil.search(type, astModel,
						javaProjects, tmpName, true));
				System.out.println("has name= --- " + resultList.size());
				System.out.println("SUPER EXECUTION NEEDED!");

				tmpName = null;
				return super.execute(resultList, operationAst, context);
			} else { // not have name constraint
				resultList.addAll(SearchUtil.search(type, astModel,
						javaProjects, "*", true));
				System.out.println("not name= --- " + resultList.size());
				System.out.println(operationAst.getFirstChild() + ":"
						+ operationAst.getFirstChild().getNextSibling());
				// return
				// context.getOperationFactory().getOperationFor("select")
				// .execute(resultList, operationAst, context);
				System.out.println("SUPER EXECUTION NEEDED!");

				// System.out.println(operationAst.getChild(1).getChild(0));
				// printAST(operationAst, "");
				return super.execute(resultList, operationAst, context);
			}

			System.out.println("select, search finished " + resultList.size());
			return resultList;

		}

		return context.getExecutorFactory().executeAST(
				operationAst.getChild(1).getChild(1), context);
		// return operationAst.getChild(1).getChild(1).getText();
	}

	protected boolean hasName(AST ast) { // check if the constrains contains name
		boolean flag = false;
		if (ast.getChildCount() != 0) {
			for (int i = 0; i < ast.getChildCount(); i++) {
				if (ast.getChild(i).getText().equals("=")
						&& (ast.getChild(i).getChild(0).getChild(1).getText()
								.equals("name") || ast.getChild(i).getChild(0)
								.getChild(1).getText().equals("fullName"))) {
					nameAst = ast.getChild(i);
					tmpName = ast.getChild(i).getChild(1).getText();
					flag = true;
				}
				if (flag) {
					break;
				} else {
					flag = hasName(ast.getChild(i));
				}
			}
		}

		return flag;
	}

	protected void printAST(AST ast, String index) {
		if (ast.getChildCount() != 0) {
			for (int i = 0; i < ast.getChildCount(); i++) {
				System.out.println("[" + index + i + "]" + ast.getChild(i)
						+ "{" + ast.getChild(i).getType() + "}");
				printAST(ast.getChild(i), index + i);
			}
		}
	}

	protected boolean checkAST(AST ast) {
		boolean flag = false;
		if (hasNot(ast)) {
			AST newAst = transformedAst(ast);
			System.out.println("AST CHANGED");
//			 printAST(newAst, "");
		}
		if (hasName(ast)) {
			while (true) {
				if (nameAst.getParent().getText().equals("select")) {
					break;
				} else if (nameAst.getParent().getText().equals("and")) {
					flag = true;
					nameAst = nameAst.getParent();
				} else {
					flag = false;
					break;
				}
			}
		}
		return flag;
	}

	protected boolean hasNot(AST ast) {
		boolean flag = false;
		if (ast.getChildCount() != 0) {
			for (int i = 0; i < ast.getChildCount(); i++) {
				if (ast.getChild(i).getText().equals("not")) {
					System.out.println(ast.getChild(i) + "!!!!!!!!!!!!!");
					flag = true;
				}
				if (flag) {
					break;
				} else {
					flag = hasNot(ast.getChild(i));
				}
			}
		}

		return flag;
	}

	// private boolean checkParent(AST ast) {
	// boolean flag = false;
	// if (ast.getParent() == null && ast.getText().equals("and")) {
	// flag = true;
	// } else {
	// flag = checkParent(ast.getParent());
	// }
	// if (ast.getParent() != null && ast.getParent().getText() != "and") {
	// flag = true;
	// if (flag) {
	// flag = checkParent(ast.getParent());
	// }
	// } else if (ast.getParent() == null) {
	// flag = true;
	// }
	// return flag;
	// }

	// private AST createAST(AST ast) {
	// for (int i = 0; i < ast.getChildCount(); i++) {
	// if (ast.getChild(i).getText().equals("or")) {
	// tmpAst.addChild(transformedAst(ast.getChild(i)));
	// }
	// }
	// return tmpAst;
	// }

	protected AST transformedAst(AST ast) {
		AST operationAst = ast;
		// while (true) {
		if (operationAst.getText().equals("not")) {
			// System.out.println("TRANSFORMING: FOUND [not]");
			if (operationAst.getChild(0).getText().equals("and")) {
				// System.out.println("TRANSFORMING: FOUND [and] under [not]");
				int index = operationAst.getChildIndex();
				AST tmpAst = new AST(operationAst);
				operationAst.getParent()
						.setChild(
								index,
								new AST(new CommonToken(EolParser.OPERATOR,
										"or"), null));
				operationAst = operationAst.getParent().getChild(index);
				operationAst.addChild(new AST(new CommonToken(
						EolParser.OPERATOR, "not"), null));
				operationAst.addChild(new AST(new CommonToken(
						EolParser.OPERATOR, "not"), null));
				operationAst.getChild(0).addChild(
						tmpAst.getChild(0).getChild(0));
				operationAst.getChild(1).addChild(
						tmpAst.getChild(0).getChild(1));
			} else if (operationAst.getChild(0).getText().equals("or")) {
				// System.out.println("TRANSFORMING: FOUND [or] under [not]");
				int index = operationAst.getChildIndex();
				// System.out.println("INDEX: "+index);
				AST tmpAst = new AST(operationAst);
				// System.out.println("PARENT: " + operationAst.getParent());
				operationAst.getParent().setChild(
						index,
						new AST(new CommonToken(EolParser.OPERATOR, "and"),
								null));
				// System.out.println("not->and: "+operationAst.getParent().getChild(index));
				operationAst = operationAst.getParent().getChild(index);
				operationAst.addChild(new AST(new CommonToken(
						EolParser.OPERATOR, "not"), null));
				operationAst.addChild(new AST(new CommonToken(
						EolParser.OPERATOR, "not"), null));
				// System.out.println("child added:" + operationAst.getChild(0)
				// + "/" +
				// operationAst.getChild(1)+"/"+operationAst.getChildCount());
				operationAst.getChild(0).addChild(
						tmpAst.getChild(0).getChild(0));
				operationAst.getChild(1).addChild(
						tmpAst.getChild(0).getChild(1));
				// printAST(operationAst.getParent(), "");
				// System.out.println();
			} else if (operationAst.getChild(0).getText().equals("not")) {
				// System.out.println("TRANSFORMING: FOUND [not] under [not]");
				int index = operationAst.getChildIndex();
				AST tmpAst = new AST(operationAst);
				operationAst.getParent().setChild(index,
						tmpAst.getChild(0).getChild(0));
				operationAst = operationAst.getParent().getChild(index);
				operationAst = transformedAst(operationAst);
			}
			// printAST(operationAst, "");
			for (int i = 0; i < operationAst.getChildCount(); i++) {
				operationAst.setChild(i,
						transformedAst(operationAst.getChild(i)));
			}
			// } else if(operationAst.getChildCount() == 0){
			// break;
		} else {
			// System.out.println("gogogo:" + operationAst.getText());
			for (int i = 0; i < operationAst.getChildCount(); i++) {
				operationAst.setChild(i,
						transformedAst(operationAst.getChild(i)));
			}
		}
		// }
		return operationAst;
	}

	// private boolean isCondition(AST testAst) {
	// if (!testAst.getText().equals("and") && !testAst.getText().equals("or"))
	// return true;
	// else
	// return false;
	// }

}
